#pragma once

#include <iostream>
#include <string>
#include <functional>
#include <strings.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "Log.hpp"

using namespace LogModule;

using func_t=std::function<std::string(const std::string&)>;
const int defaultfd=-1;

class UdpServer
{
    public:
    UdpServer(uint16_t port,func_t func)
    :_sockfd(defaultfd),
    //_ip(ip)
    _port(port),
    _isrunning(false),
    _func(func)
    {}
    void Init()
    {
        //1.创建套接字
        _sockfd = socket(AF_INET, SOCK_DGRAM, 0);
        if (_sockfd < 0)
        {
            LOG(LogLevel::FATAL) << "socket error!";
            exit(1);
        }
        LOG(LogLevel::INFO) << "socket success, sockfd : " << _sockfd;
        //填充信息
        struct sockaddr_in local;
        bzero(&local,sizeof(local));
        local.sin_family=AF_INET;
        local.sin_port=htons(_port);//转网络大端
        //local.sin_addr.s_addr=inet_addr(_ip.c_str());
        local.sin_addr.s_addr=INADDR_ANY;
        //bind，用户层的数据结构拷贝到内核中
        int n=bind(_sockfd,(struct sockaddr*)&local,sizeof(local));
        if (n < 0)
        {
            LOG(LogLevel::FATAL) << "bind error";
            exit(2);
        }
        LOG(LogLevel::INFO) << "bind success, sockfd : " << _sockfd;
    }

    void Start()
    {
        _isrunning=true;
        while(_isrunning)
        {
            char buffer[1024];
            struct sockaddr_in peer;
            socklen_t len=sizeof(peer);
            ssize_t s=recvfrom(_sockfd,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&peer,&len);
            if(s>0)
            {
                //LOG(LogLevel::DEBUG) << "[" << peer_ip << ":" << peer_port<< "]# " << buffer; // 1. 消息内容 2. 谁发的？？
                std::string echo_string = "server echo@ ";
                echo_string += buffer;
                //0表示阻塞类似scanf
                sendto(_sockfd, echo_string.c_str(), echo_string.size(), 0, (struct sockaddr*)&peer, len);
            }
        }
    }
    ~UdpServer()
    {

    }
    private:
    int _sockfd;
    uint16_t _port;
    //std::string _ip;//点分十进制的字符串,不需要了，因为bind INADDR_ANY
    bool _isrunning;
    func_t _func;//回调函数
};